package com.ruoyi.miniapp.service.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ruoyi.common.core.domain.miniapp.MiniAppUser;
import com.ruoyi.common.security.manager.WxMaServiceManager;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.map.SoMap;
import com.ruoyi.miniapp.domain.TMiniSportRecord;
import com.ruoyi.miniapp.mapper.TMiniSportRecordMapper;
import com.ruoyi.miniapp.service.ITMiniSportRecordService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 运动记录Service业务层处理
 * 
 * @author ruoyi
 * @date 2025-07-17
 */
@Service
@Slf4j
public class TMiniSportRecordServiceImpl extends ServiceImpl<TMiniSportRecordMapper,TMiniSportRecord> implements ITMiniSportRecordService
{
    @Autowired
    private TMiniSportRecordMapper tMiniSportRecordMapper;

    @Autowired
    private WxMaServiceManager wxMaServiceManager;

    /**
     * 查询运动记录
     * 
     * @param recordId 运动记录主键
     * @return 运动记录
     */
    @Override
    public TMiniSportRecord selectTMiniSportRecordByRecordId(Long recordId)
    {
        return tMiniSportRecordMapper.selectTMiniSportRecordByRecordId(recordId);
    }

    /**
     * 查询运动记录列表
     * 
     * @param tMiniSportRecord 运动记录
     * @return 运动记录
     */
    @Override
    public List<TMiniSportRecord> selectTMiniSportRecordList(TMiniSportRecord tMiniSportRecord)
    {

        return tMiniSportRecordMapper.selectTMiniSportRecordList(tMiniSportRecord);
    }

    /**
     * 新增运动记录
     * 
     * @param tMiniSportRecord 运动记录
     * @return 结果
     */
    @Override
    public int insertTMiniSportRecord(TMiniSportRecord tMiniSportRecord)
    {
        tMiniSportRecord.setCreateTime(DateUtils.getNowDate());
        return tMiniSportRecordMapper.insertTMiniSportRecord(tMiniSportRecord);
    }

    /**
     * 修改运动记录
     * 
     * @param tMiniSportRecord 运动记录
     * @return 结果
     */
    @Override
    public int updateTMiniSportRecord(TMiniSportRecord tMiniSportRecord)
    {
        tMiniSportRecord.setUpdateTime(DateUtils.getNowDate());
        return tMiniSportRecordMapper.updateTMiniSportRecord(tMiniSportRecord);
    }

    /**
     * 批量删除运动记录
     * 
     * @param recordIds 需要删除的运动记录主键
     * @return 结果
     */
    @Override
    public int deleteTMiniSportRecordByRecordIds(Long[] recordIds)
    {
        return tMiniSportRecordMapper.deleteTMiniSportRecordByRecordIds(recordIds);
    }

    /**
     * 删除运动记录信息
     * 
     * @param recordId 运动记录主键
     * @return 结果
     */
    @Override
    public int deleteTMiniSportRecordByRecordId(Long recordId)
    {
        return tMiniSportRecordMapper.deleteTMiniSportRecordByRecordId(recordId);
    }

    /**
     * 保存运动记录
     * @param params 运动记录数据包
     * @return
     */
    @Override
    public int batchSaveSport(SoMap params) {
        AtomicInteger saveCount = new AtomicInteger();
        // 获取包含 category 和 sport 数据的列表
        List<JSONObject> cartList = params.getList("cartData", JSONObject.class);

        // 判断如果数据列表为空直接返回 0
        if (cartList == null || cartList.isEmpty()) {
            return saveCount.get();
        }
        MiniAppUser miniAppUser=SecurityUtils.getLoginUser().getMiniAppUser();
        for (JSONObject cartItem : cartList) {
            JSONArray sportList = cartItem.getJSONArray("list");
            if (sportList == null || sportList.isEmpty()) {
                continue;
            }
            // 遍历每个 sport
            sportList.forEach(sport -> {
                log.info("sport:{}", JSON.toJSONString(sport));
                if (sport instanceof JSONObject) {
                    JSONObject sportData= (JSONObject) sport;
                    TMiniSportRecord record = new TMiniSportRecord();
                    // 获取当前登陆用户的信息
                    record.setUserId(miniAppUser.getId());
                    record.setOpenId(miniAppUser.getOpenId());
                    // 从 JSON 对象中提取数据并设置到运动记录对象中
                    if (sportData.containsKey("id")) {
                        record.setSportId(sportData.getLong("id"));
                    }
                    if (sportData.containsKey("name")) {
                        record.setSportName(sportData.getString("name"));
                    }
                    if (sportData.containsKey("calorie")) {
                        record.setCalorie(sportData.getString("calorie"));
                    }
                    if (sportData.containsKey("unit")) {
                        record.setTime(sportData.getLong("unit"));
                    }
                    if (sportData.containsKey("selected")) {
                         record.setNum(sportData.getLong("selected"));
                    }
                    // 设置创建时间
                    record.setRecordTime(DateUtils.getToday());
                    record.setCreateTime(DateUtils.getNowDate());
                    // 调用插入方法并累加成功数量
                    int insertResult = tMiniSportRecordMapper.insertTMiniSportRecord(record);
                    if(insertResult>0){
                        saveCount.getAndIncrement();
                    }

                }
            });
        }
        return saveCount.get();
    }

    /**
     * 解密微信运动步数
     * @param params
     * @return
     */
    @Override
    public JSONObject dencryptSportData(SoMap params) {
        try {
            WxMaService wxMaService = wxMaServiceManager.getWxMaService(params.getString("appid"));
            WxMaJscode2SessionResult sessionResult = wxMaService.jsCode2SessionInfo(params.getString("code"));
            JSONObject result = decrypt(
                    params.getString("encryptedData"),
                    sessionResult.getSessionKey(),
                    params.getString("iv")
            );
            return result;
        }catch (Exception e) {
            log.error("微信运动数据解密失败", e);
        }
        return null;
    }

    /**
     * 解密微信小程序手机号
     * @param encryptedData 加密数据
     * @param sessionKey    会话密钥
     * @param iv            加密向量
     * @return 解密后的 JSON 对象
     * @throws Exception 解密异常
     */
    public static JSONObject decrypt(String encryptedData, String sessionKey, String iv) throws Exception {
        // 1. Base64 解码
        byte[] encryptedDataBytes = org.apache.commons.codec.binary.Base64.decodeBase64(encryptedData);
        byte[] sessionKeyBytes = org.apache.commons.codec.binary.Base64.decodeBase64(sessionKey);
        byte[] ivBytes = Base64.decodeBase64(iv);

        // 2. AES-128-CBC 解密
        SecretKeySpec secretKeySpec = new SecretKeySpec(sessionKeyBytes, "AES");
        IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);

        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
        byte[] decryptedBytes = cipher.doFinal(encryptedDataBytes);

        // 3. 转换为 JSON
        String decryptedStr = new String(decryptedBytes, "UTF-8");
        return JSONObject.parseObject(decryptedStr);
    }

    /**
     * 根据运动类型统计用户每日运动量
     * @param params
     * @return
     */
    @Override
    public List anlysisSportType(SoMap params) {
        // 按照运动类型统计用户当日运动情况
        MiniAppUser miniAppUser=SecurityUtils.getLoginUser().getMiniAppUser();
        params.put("userId",miniAppUser.getId());
        params.put("openId",miniAppUser.getOpenId());
        return tMiniSportRecordMapper.selectTMiniSportRecordChart(params);
    }

    /**
     * 分页查询运动记录
     * @param so
     * @return
     */
    @Override
    public PageInfo<TMiniSportRecord> getSportHistoryList(SoMap so) {
        PageHelper.startPage(so.getInt("pageNum", 1), so.getInt("pageSize", 10));
        LambdaQueryWrapper<TMiniSportRecord> lqw = new LambdaQueryWrapper();
        lqw.eq(StringUtils.isNotEmpty(so.getString("userId")), TMiniSportRecord::getUserId, so.getString("userId"));
        lqw.eq(StringUtils.isNotEmpty(so.getString("openId")), TMiniSportRecord::getOpenId, so.getString("openId"));
        lqw.orderByDesc(TMiniSportRecord::getCreateTime);
        List<TMiniSportRecord> sportRecordList = tMiniSportRecordMapper.selectList(lqw);
        PageInfo<TMiniSportRecord> pageInfo = new PageInfo<>(sportRecordList);
        return pageInfo;
    }

    /**
     * 查询今日运动记录
     * @param so
     * @return
     */
    @Override
    public List<TMiniSportRecord> getTodaySportHistory(SoMap so) {
        // 如果传入的date为空则设置日期为当日日期
        if (so == null || so.get("date") == null || so.get("date").toString().isEmpty()) {
            Date today = DateUtils.getToday();
            so.put("date",DateUtils.parseDateToStr("yyyy-MM-dd",today));
        }
        LambdaQueryWrapper<TMiniSportRecord> lqw = new LambdaQueryWrapper();
        lqw.eq(StringUtils.isNotEmpty(so.getString("userId")), TMiniSportRecord::getUserId, so.getString("userId"));
        lqw.eq(StringUtils.isNotEmpty(so.getString("openId")), TMiniSportRecord::getOpenId, so.getString("openId"));
        lqw.eq(StringUtils.isNotEmpty(so.getString("date")), TMiniSportRecord::getRecordTime, so.getString("date"));
        lqw.orderByDesc(TMiniSportRecord::getCreateTime);
        List<TMiniSportRecord> sportRecordList = tMiniSportRecordMapper.selectList(lqw);
        return sportRecordList;
    }

    /**
     * 统计用户运动记录数量
     * @param params
     * @return
     */
    @Override
    public int getSportRecordUserCount(SoMap params) {
        params.put("recordTime", DateUtils.getDateBeforeDays(-1));
        return tMiniSportRecordMapper.selectSportRecordUserCount(params);
    }

}
